use serde::{Deserialize, Serialize};
use std::collections::HashMap;
use std::net::SocketAddr;
use std::time::Duration;

#[derive(Debug, Clone, Deserialize, Serialize)]
pub struct ServerConfig {
    pub listen: SocketAddr,

    #[serde(default)]
    pub obfs: ObfsConfig,

    pub tls: Option<TlsConfig>,

    #[serde(default)]
    pub bandwidth: BandwidthConfig,

    #[serde(default)]
    pub ignore_client_bandwidth: bool,

    #[serde(default)]
    pub disable_udp: bool,

    #[serde(default = "default_udp_idle_timeout")]
    pub udp_idle_timeout: Duration,

    pub auth: AuthConfig,

    pub traffic_stats: Option<TrafficStatsConfig>,

    #[serde(default)]
    pub masquerade: MasqueradeConfig,
}

fn default_udp_idle_timeout() -> Duration {
    Duration::from_secs(60)
}

#[derive(Debug, Clone, Default, Deserialize, Serialize)]
pub struct ObfsConfig {
    #[serde(rename = "type")]
    pub obfs_type: Option<String>,
    pub salamander: Option<SalamanderConfig>,
}

#[derive(Debug, Clone, Deserialize, Serialize)]
pub struct SalamanderConfig {
    pub password: String,
}

#[derive(Debug, Clone, Deserialize, Serialize)]
pub struct TlsConfig {
    pub cert: String,
    pub key: String,
}

#[derive(Debug, Clone, Default, Deserialize, Serialize)]
pub struct BandwidthConfig {
    #[serde(default)]
    pub up: String,
    #[serde(default)]
    pub down: String,
}

#[derive(Debug, Clone, Deserialize, Serialize)]
#[serde(tag = "type", rename_all = "lowercase")]
pub enum AuthConfig {
    Password {
        password: String,
    },
    #[serde(rename = "userpass")]
    UserPass {
        userpass: HashMap<String, String>,
    },
    Http {
        url: String,
        #[serde(default)]
        insecure: bool,
    },
}

#[derive(Debug, Clone, Deserialize, Serialize)]
pub struct TrafficStatsConfig {
    pub listen: SocketAddr,
    pub secret: String,
}

#[derive(Debug, Clone, Default, Deserialize, Serialize)]
pub struct MasqueradeConfig {
    #[serde(rename = "type")]
    pub masq_type: Option<String>,
    pub proxy: Option<ProxyMasqueradeConfig>,
}

#[derive(Debug, Clone, Deserialize, Serialize)]
pub struct ProxyMasqueradeConfig {
    pub url: String,
    #[serde(default)]
    pub rewrite_host: bool,
}

impl ServerConfig {
    pub fn from_file(path: &str) -> anyhow::Result<Self> {
        let content = std::fs::read_to_string(path)?;
        let config = serde_yaml::from_str(&content)?;
        Ok(config)
    }

    pub fn parse_bandwidth(&self) -> (u64, u64) {
        (
            parse_bandwidth_string(&self.bandwidth.up),
            parse_bandwidth_string(&self.bandwidth.down),
        )
    }
}

fn parse_bandwidth_string(s: &str) -> u64 {
    if s.is_empty() {
        return 0;
    }

    let s = s.trim().to_lowercase();
    let (num_str, unit) = if let Some(pos) = s.find(|c: char| c.is_alphabetic()) {
        s.split_at(pos)
    } else {
        return s.parse().unwrap_or(0);
    };

    let num: f64 = num_str.trim().parse().unwrap_or(0.0);
    let multiplier = match unit.trim() {
        "bps" => 1.0,
        "kbps" => 1_000.0,
        "mbps" => 1_000_000.0,
        "gbps" => 1_000_000_000.0,
        "kb" => 1_024.0,
        "mb" => 1_048_576.0,
        "gb" => 1_073_741_824.0,
        _ => 1.0,
    };

    (num * multiplier) as u64
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_parse_bandwidth() {
        assert_eq!(parse_bandwidth_string("100 mbps"), 100_000_000);
        assert_eq!(parse_bandwidth_string("1 gbps"), 1_000_000_000);
        assert_eq!(parse_bandwidth_string("500kbps"), 500_000);
    }
}
